#include "inorder/dram.h"

uint64_t DramOP::dram_op_id = 0;

namespace config
{
    const Value<uint64_t> dram_read_latency = {"dram_read_latency", 4, "dram read latency"};
    const Value<uint64_t> dram_write_latency = {"dram_write_latency", 6, "dram write latency"};
    const Value<uint64_t> dram_outstanding_num = {"dram_outstanding_num", 8, "dram outstanding num"};

} // namespace config

BasicDram::BasicDram()
{
    reset();
}
BasicDram::~BasicDram()
{
}
void BasicDram::reset()
{
    cycle = 0;
    reqs.clear();
}
bool BasicDram::send(DramOP *op)
{
    if (reqs.size() >= config::dram_outstanding_num)
        return false;
    reqs.push_back(std::make_tuple(op, cycle));
    return true;
}
bool BasicDram::recv(DramOP *op)
{
    auto it = std::find_if(reqs.begin(), reqs.end(), [op](DramReq &req)
                           { return op->id == std::get<0>(req)->id; });

    if (it == reqs.end())
    {
        SPDLOG_ERROR("[Dram] Couldn't find Memory OP {} in request list.", op->id);
        return false;
    }

    auto mop = std::get<0>(*it);
    auto mcycle = std::get<1>(*it);

    uint64_t ready_cycle;
    if (mop->write)
    {
        ready_cycle = mcycle + config::dram_write_latency;
    }
    else
    {
        ready_cycle = mcycle + config::dram_read_latency;
    }

    if (ready_cycle >= cycle)
    {
        return false;
    }
    else
    {
        SPDLOG_TRACE("[Dram] Memory OP {} ready to return.", op->id);
        reqs.erase(it);
        return true;
    }
}
void BasicDram::run()
{
    cycle++;
}
